/* Copyright (C) 2010  Romolo Camplani, Marco Fortunato, Marco Marelli, Guido Rota, Fabio A. Schreiber et al.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package org.dei.perla.sys.persistence;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.SQLException;

/**
 * Mappa in java il tipo sql Blob, implementando l'interfaccia messa a disposizione dal 
 * pacchetto java.sql.
 * @author Luigi Rinaldi & Matteo Rovero
 *
 */
public class BlobSql implements Blob {
	
	private byte pdata[];
	
	/**
	 * Costruttore da tipo base byte
	 * @param parData
	 */
	public BlobSql(byte parData[]) {
		this.pdata = parData;		
	}
	
	/**
	 * Costruttore da array di byte
	 * @param parData array di byte
	 */
	public BlobSql(Byte parData[]) {
		this.pdata = new byte[parData.length];
		
		for (int i = 0; i < parData.length; i++) {
			this.pdata[i] = parData[i];
		}
	 }

	@Override
	public void free() throws SQLException {
		if(this.pdata != null) this.pdata = null;
		else throw new SQLException();
	}

	@Override
	public InputStream getBinaryStream() throws SQLException {
		if(this.pdata == null) throw new SQLException();
		ByteArrayInputStream stream = new ByteArrayInputStream(pdata);
		return stream;
	}

	@Override
	public InputStream getBinaryStream(long pos, long length) throws SQLException {
		if(this.pdata == null) throw new SQLException();
		if(pos < 1 || length <= 0||(pos-1)+length > this.pdata.length) throw new SQLException();
		
		ByteArrayInputStream stream = null;
		byte array [] = new byte[(int) length];
		
		for(int i = (int)(pos-1); i < (pos-1)+length; i++){
			array [i-(int)(pos-1)]= this.pdata[i];
		}	
		stream = new ByteArrayInputStream(array);
	    return stream; 
	}

	@Override
	public byte[] getBytes(long pos, int length) throws SQLException {
		if(this.pdata == null) throw new SQLException();
		if(pos < 1 || length <= 0 || (pos-1)+length > this.pdata.length) throw new SQLException();
		byte array [] = new byte[length];
		for(int i=0; i < length; i++){
			array [i]= this.pdata[(int) (i+(pos-1))];
		}	
		return array;
	}
	

	@Override
	public long length()throws SQLException {
		if(this.pdata == null) throw new SQLException();
		
		return pdata.length;
	}


	@Override
	public long position(byte[] pattern, long start) throws SQLException {
		if(this.pdata == null) throw new SQLException();
		if(start < 1) throw new SQLException();
		int end = this.pdata.length;
		boolean check;
		for(int begin = (int) (start-1); begin < end && pattern.length <= end-begin; begin++){
			check=true;
			for(int k=begin; k<begin+pattern.length; k++){
				if(this.pdata[k]!= pattern[k-begin])
					check=false;
			}
			
			if(check)
				return begin+1;
		}
		return -1;	
	}
	
	@Override
	public long position(Blob pattern, long start) throws SQLException {
		return position(pattern.getBytes(1,(int) pattern.length()),start);
	}

	@Override
	public OutputStream setBinaryStream(long pos) throws SQLException {
		if(this.pdata == null) throw new SQLException();
		if(pos < 1) throw new SQLException();
		
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		byte array[] = new byte[pdata.length];
			
		for(int i = (int)(pos-1); i < pdata.length; i++ ){
				array[i - (int)(pos-1)] = pdata[i];
		}
		try {
			stream.write(array);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return stream;
	}

	@Override
	public int setBytes(long pos, byte[] bytes) throws SQLException {
		if(this.pdata == null) throw new SQLException();
		if(pos < 1) throw new SQLException();
		
		int count = 0;
		byte b[] = new byte[(int) ((pos-1) + bytes.length)];
		for(int i =0; i < (int) ((pos-1) + bytes.length); i++){
			if(i<(pos-1))
				b[i] = pdata[i];
			else{
				b[i]= bytes[i -(int)(pos-1)];
				count++;
			}
		}
		this.pdata = b;
		return count;  

	}

	@Override
	public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {
		if(this.pdata == null) throw new SQLException();
		if(pos < 1 || offset < 0 || (offset-1) > bytes.length || len <=0 || len > (offset-1)+bytes.length) throw new SQLException();
		
		byte b[] = new byte[(int) (len)];
		for(int i=0; i<len; i++){
			b[i]=bytes[i+(offset-1)];
		}
		
		return setBytes(pos,b);
	}

	@Override
	public void truncate(long len) throws SQLException {
		if(this.pdata == null) throw new SQLException();
		if(len <= 0) throw new SQLException();
		
		byte temp[] = new byte[(int) len];
		
		for(int i = 0; i < (int)len; i++){
				temp[i] = pdata[i];
			}
		this.pdata = temp;
		
	}
	@Override
	public boolean equals(Object b) {
		try {
			if(this.pdata.length != ((BlobSql) b).length())
				return false;
		} catch (SQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		for(int i=0; i<this.pdata.length; i++){
			try {
				if(this.pdata[i] != ((BlobSql) b).getBytes(1,(int)((BlobSql) b).length())[i])
					return false;
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}		
		}
		return true;
	}

}

